package utils

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

// CalculateMD5 计算文件的MD5值
func CalculateMD5(filePath string) (string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		return "", err
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}

// FileExists 检查文件是否存在
func FileExists(filePath string) bool {
	info, err := os.Stat(filePath)
	if os.IsNotExist(err) {
		return false
	}
	return !info.IsDir()
}

// DirExists 检查目录是否存在
func DirExists(dirPath string) bool {
	info, err := os.Stat(dirPath)
	if os.IsNotExist(err) {
		return false
	}
	return info.IsDir()
}

// EnsureDir 确保目录存在，如果不存在则创建
func EnsureDir(dirPath string) error {
	return os.MkdirAll(dirPath, 0755)
}

// GetFileSize 获取文件大小
func GetFileSize(filePath string) (int64, error) {
	info, err := os.Stat(filePath)
	if err != nil {
		return 0, err
	}
	return info.Size(), nil
}

// GetFileModTime 获取文件修改时间
func GetFileModTime(filePath string) (time.Time, error) {
	info, err := os.Stat(filePath)
	if err != nil {
		return time.Time{}, err
	}
	return info.ModTime(), nil
}

// IsTextFile 判断是否为文本文件
func IsTextFile(filePath string) bool {
	file, err := os.Open(filePath)
	if err != nil {
		return false
	}
	defer file.Close()

	// 读取文件前512字节用于判断文件类型
	buffer := make([]byte, 512)
	n, err := file.Read(buffer)
	if err != nil && err != io.EOF {
		return false
	}

	// 检查是否为文本文件
	for i := 0; i < n; i++ {
		if buffer[i] == 0 {
			// 包含空字节，可能是二进制文件
			return false
		}
	}

	return true
}

// GetFileExtension 获取文件扩展名
func GetFileExtension(filePath string) string {
	return strings.ToLower(filepath.Ext(filePath))
}

// GetFileName 获取文件名（不包含路径和扩展名）
func GetFileName(filePath string) string {
	return strings.TrimSuffix(filepath.Base(filePath), filepath.Ext(filePath))
}

// GetRelativePath 获取相对路径
func GetRelativePath(basePath, filePath string) (string, error) {
	// 确保路径是绝对路径
	if !filepath.IsAbs(basePath) {
		absPath, err := filepath.Abs(basePath)
		if err != nil {
			return "", err
		}
		basePath = absPath
	}

	if !filepath.IsAbs(filePath) {
		absPath, err := filepath.Abs(filePath)
		if err != nil {
			return "", err
		}
		filePath = absPath
	}

	// 获取相对路径
	relPath, err := filepath.Rel(basePath, filePath)
	if err != nil {
		return "", err
	}

	return relPath, nil
}

// NormalizePath 规范化路径
func NormalizePath(path string) string {
	// 替换路径分隔符
	path = filepath.ToSlash(path)

	// 去除末尾的斜杠
	path = strings.TrimRight(path, "/")

	// 替换连续的斜杠
	for strings.Contains(path, "//") {
		path = strings.ReplaceAll(path, "//", "/")
	}

	return path
}

// CleanText 清理文本内容
func CleanText(text string) string {
	// 替换多个空白字符为单个空格
	re := regexp.MustCompile(`\s+`)
	text = re.ReplaceAllString(text, " ")

	// 去除首尾空格
	text = strings.TrimSpace(text)

	return text
}

// TruncateText 截断文本
func TruncateText(text string, maxLength int) string {
	if len(text) <= maxLength {
		return text
	}
	return text[:maxLength] + "..."
}

// FormatBytes 格式化字节数
func FormatBytes(bytes int64) string {
	const unit = 1024
	if bytes < unit {
		return fmt.Sprintf("%d B", bytes)
	}
	div, exp := int64(unit), 0
	for n := bytes / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}
	return fmt.Sprintf("%.1f %ciB", float64(bytes)/float64(div), "KMGTPE"[exp])
}

// FormatDuration 格式化持续时间
func FormatDuration(d time.Duration) string {
	if d < time.Minute {
		return fmt.Sprintf("%.2fs", d.Seconds())
	}
	if d < time.Hour {
		return fmt.Sprintf("%.2fm", d.Minutes())
	}
	if d < 24*time.Hour {
		return fmt.Sprintf("%.2fh", d.Hours())
	}
	return fmt.Sprintf("%.2fd", d.Hours()/24)
}

// ContainsString 检查字符串切片是否包含指定字符串
func ContainsString(slice []string, item string) bool {
	for _, s := range slice {
		if s == item {
			return true
		}
	}
	return false
}

// RemoveString 从字符串切片中移除指定字符串
func RemoveString(slice []string, item string) []string {
	var result []string
	for _, s := range slice {
		if s != item {
			result = append(result, s)
		}
	}
	return result
}

// UniqueStrings 去重字符串切片
func UniqueStrings(slice []string) []string {
	keys := make(map[string]bool)
	var result []string
	for _, s := range slice {
		if !keys[s] {
			keys[s] = true
			result = append(result, s)
		}
	}
	return result
}

// MergeMaps 合并两个map
func MergeMaps(maps ...map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for _, m := range maps {
		for k, v := range m {
			result[k] = v
		}
	}
	return result
}

// SafeFileName 安全的文件名（移除特殊字符）
func SafeFileName(fileName string) string {
	// 替换特殊字符为下划线
	re := regexp.MustCompile(`[\\/:*?"<>|]`)
	return re.ReplaceAllString(fileName, "_")
}

// ReadFileToString 读取文件到字符串
func ReadFileToString(filePath string) (string, error) {
	bytes, err := os.ReadFile(filePath)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

// WriteStringToFile 将字符串写入文件
func WriteStringToFile(filePath, content string) error {
	return os.WriteFile(filePath, []byte(content), 0644)
}

// AppendStringToFile 将字符串追加到文件
func AppendStringToFile(filePath, content string) error {
	file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = file.WriteString(content)
	return err
}

// CopyFile 复制文件
func CopyFile(src, dst string) error {
	source, err := os.Open(src)
	if err != nil {
		return err
	}
	defer source.Close()

	destination, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer destination.Close()

	_, err = io.Copy(destination, source)
	return err
}

// SplitTextByLines 按行分割文本
func SplitTextByLines(text string) []string {
	return strings.Split(text, "\n")
}

// JoinLinesByString 用指定字符串连接行
func JoinLinesByString(lines []string, separator string) string {
	return strings.Join(lines, separator)
}

// CountLines 计算文本行数
func CountLines(text string) int {
	if text == "" {
		return 0
	}
	return len(strings.Split(text, "\n"))
}

// CountWords 计算文本单词数
func CountWords(text string) int {
	if text == "" {
		return 0
	}
	// 简单实现，按空白字符分割
	words := strings.Fields(text)
	return len(words)
}

// CountCharacters 计算文本字符数
func CountCharacters(text string) int {
	return len([]rune(text))
}

// ReverseString 反转字符串
func ReverseString(s string) string {
	r := []rune(s)
	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}
	return string(r)
}

// IsURL 判断是否为URL
func IsURL(str string) bool {
	re := regexp.MustCompile(`^https?://[\w\-]+(\.[\w\-]+)+[\w\-\.,@?^=%&:/~\+#]*$`)
	return re.MatchString(str)
}

// IsEmail 判断是否为邮箱
func IsEmail(str string) bool {
	re := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
	return re.MatchString(str)
}

// IsNumeric 判断是否为数字
func IsNumeric(str string) bool {
	re := regexp.MustCompile(`^\d+$`)
	return re.MatchString(str)
}

// IsAlpha 判断是否为字母
func IsAlpha(str string) bool {
	re := regexp.MustCompile(`^[a-zA-Z]+$`)
	return re.MatchString(str)
}

// IsAlphanumeric 判断是否为字母数字
func IsAlphanumeric(str string) bool {
	re := regexp.MustCompile(`^[a-zA-Z0-9]+$`)
	return re.MatchString(str)
}

// MaskString 掩码字符串
func MaskString(str string, start, end int, maskChar rune) string {
	if str == "" {
		return ""
	}

	runes := []rune(str)
	length := len(runes)

	if start < 0 {
		start = 0
	}
	if end > length {
		end = length
	}
	if start >= end {
		return str
	}

	for i := start; i < end; i++ {
		runes[i] = maskChar
	}

	return string(runes)
}

// GenerateUUID 生成UUID
func GenerateUUID() string {
	b := make([]byte, 16)
	_, err := io.ReadFull(bytes.NewReader([]byte(time.Now().String())), b)
	if err != nil {
		panic(err) // 如果读取随机数失败，直接panic
	}
	b[6] = (b[6] & 0x0F) | 0x40
	b[8] = (b[8] & 0x3F) | 0x80
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}